/*************************************************************
*
* DS_ALLOCATOR.HPP
* 
*************************************************************/

template <class T>
dsNODE_CACHE<T>::dsNODE_CACHE(/*apCL cl*/) : nNode(0), nodeList(/*cl*/) 
#ifdef AP_USE_MEM_STAT
, __cl(cl)
#endif
{
}

/***************************************************************
* dsNODE_CACHE<T>::Init ()
*
***************************************************************/
template <class T> BOOL dsNODE_CACHE<T>::Init (int _nNode)
{  
   nNode = _nNode;
   return AddNodes();
}
/***************************************************************
* dsNODE_CACHE<T>::Term ()
*
***************************************************************/
template <class T> void dsNODE_CACHE<T>::Term (void)
{  
   freeNodeList.Clear();

   for (int i = 0; i < nodeList.Length(); i++) {
      delete[] nodeList[i];
   }
   nodeList.Clear();
   nodeList.Compact();
   nNode = 0;
   return ;
}

/***************************************************************
* dsNODE_CACHE<T>::Free ()
*
***************************************************************/
template <class T> void dsNODE_CACHE<T>::Free ()
{
   freeNodeList.Clear();

   for (int i = 0; i < nodeList.Length(); i++) {
      delete[] nodeList[i];
   }
   nodeList.Free();
   nNode = 0;
   return ;
}

/***************************************************************
* dsNODE_CACHE<T>::GetEmpty ()
*
***************************************************************/
template <class T> T* dsNODE_CACHE<T>::GetEmpty (void)
{ 
   if (freeNodeList.IsEmpty()) {
      AddNodes();
   }
   typename FREE_LIST::ITERATOR it = freeNodeList.Front();
   T *pNode = it.Get();
   freeNodeList.Erase(it); 

   return pNode; 
}
/***************************************************************
* dsNODE_CACHE<T>::Init ()
*
***************************************************************/
template <class T> BOOL dsNODE_CACHE<T>::AddNodes (void)
{  
   // if not inited
   if (nNode == 0) {
      nNode = 16;
   }

#if defined(AP_USE_MEM_STAT) && !defined(__PLUGIN__)
   T * nodeList_ = new(__cl.file, __cl.line) T[nNode];
#else
   T * nodeList_ = apNEW T[nNode];
#endif

   if (nodeList_ == NULL) {
      return FALSE;
   }
   for (int i = 0; i < nNode; i ++) {
      Release(&nodeList_[i]);
   }
   nodeList.PushBack(nodeList_);
   return TRUE;
}

namespace ds {

/******************************************************************************/
/* ds::FIXED_SIZE_ALLOCATOR<T>::Alloc
/*
/******************************************************************************/
template <class T>
T * FIXED_SIZE_ALLOCATOR::Alloc(void)
{
   BYTE * res = (BYTE *)_Alloc(sizeof(T));
   return new (res) T();
}

/******************************************************************************/
/* ds::FIXED_SIZE_ALLOCATOR<T>::Alloc
/*
/******************************************************************************/
template <class T, class V>
T * FIXED_SIZE_ALLOCATOR::Alloc(const V & p)
{
   BYTE * res = (BYTE *)_Alloc(sizeof(T));
   return new (res) T(p);
}

/******************************************************************************/
/* ds::FIXED_SIZE_ALLOCATOR<T>::Free
/*
/******************************************************************************/
template <class T>
void FIXED_SIZE_ALLOCATOR::Free(T * ptr)
{
   if (ptr == NULL) {
      return ;
   }

   ptr->~T();
   _Free(ptr, sizeof(T));
}

/******************************************************************************/
/* ds::FIXED_SIZE_ALLOCATOR::AllocAlign
/*
/******************************************************************************/
template <class T>
T * FIXED_SIZE_ALLOCATOR::AllocAlign(int align)
{
   int size = sizeof(T) + 4 + align - 1; // size + offset
   if (size & (align - 1)) {
      size = (size + align) & ~(align - 1);
   }

   BYTE * data = (BYTE *)_Alloc(size);

   int offset = align - ((int)data + 4) & (align - 1);
   *(int *)(data + offset) = offset + 4; // store total offset

   STRONG_ASSERT(int(data + offset + 4) % align == 0);

   return new (data + offset + 4) T();
}

/******************************************************************************/
/* ds::FIXED_SIZE_ALLOCATOR::FreeAlign
/*
/******************************************************************************/
template <class T>
void FIXED_SIZE_ALLOCATOR::FreeAlign(T * ptr, int align)
{
   if (ptr == NULL) {
      return ;
   }

   ptr->~T();

   int size = sizeof(T) + 4 + align - 1; // size + offset
   if (size & (align - 1)) {
      size = (size + align) & ~(align - 1);
   }

   int offset = ((int *)ptr)[-1];
   _Free((BYTE *)ptr - offset, size);
}

/******************************************************************************/
/* ds::FIXED_SIZE_ALLOCATOR<T>::AllocArray
/*
/******************************************************************************/
template <class T>
T * FIXED_SIZE_ALLOCATOR::AllocArray(int count)
{
   BYTE * res = (BYTE *)_Alloc(sizeof(T) * count);
   for (int k = 0; k < count; ++k) {
      new (res + k * sizeof(T)) T();
   }
   return (T *)res;
}

/******************************************************************************/
/* ds<T>::FreeArray
/*
/******************************************************************************/
template <class T>
void FIXED_SIZE_ALLOCATOR::FreeArray(T * ptr, int count)
{
   if (ptr == NULL) {
      return ;
   }

   for (int k = 0; k < count; ++k) {
      ptr[k].~T();
   }
   _Free(ptr, count * sizeof(T));
}

} // namespace ds

//
// End-of-file DS_ALLOCATOR.HPP
//
